<?php
namespace Uploadcare;

class Uploader
{
	/**
	 * Base upload host
	 * 
	 * @var string
	 **/
	private $host = 'upload.uploadcare.com';
	
	/**
	 * Api instance
	 * 
	 * @var Api
	 **/
	private $api = null;
	
	/**
	 * Constructor
	 **/
	public function __construct(Api $api)
	{
		$this->api = $api;
	}
	
	/**
	 * Check file status.
	 * Return array of json data
	 * 
	 * @param string $file_id 
	 * @return array
	 **/
	public function status($token)
	{		
		$data = array(
				'token' => $token,
		);
		$ch = $this->__initRequest('status', $data);
		$this->__setHeaders($ch);
		$data = $this->__runRequest($ch);
		return $data;
	}
	
	/**
	 * Upload file from url and get File instance
	 * 
	 * @param string $url An url of file to be uploaded.
	 * @return File
	 **/
	public function fromUrl($url, $check_status = true, $timeout = 1, $max_attempts = 5)
	{
		$data = array(
				'_' => time(),
				'source_url' => $url,
				'pub_key' => $this->api->getPublicKey(),
		);
		$ch = $this->__initRequest('from_url', $data);
		$this->__setHeaders($ch);

		$data = $this->__runRequest($ch);
		$token = $data->token;
		
		if ($check_status) {
			$success = false;
			$attempts = 0;
			while (!$success) {
				$data = $this->status($token);
				if ($data->status == 'success') {
					$success = true;
				}
				if ($attempts == $max_attempts) {
					throw new \Exception('Cannot store file, max attempts reached, upload is not successful');
				}
				sleep($timeout);
				$attempts++;
			}
		} else {
			return $token;
		}		
		$file_id = $data->file_id;
		
		return new File($file_id, $this->api);
	}
	
	/**
	 * Upload file from local path.
	 * 
	 * @param string $path
	 * @return File
	 **/
	public function fromPath($path)
	{
		$data = array(
				'UPLOADCARE_PUB_KEY' => $this->api->getPublicKey(),
				'file' => '@'.$path,
		);
		$ch = $this->__initRequest('base');
		$this->__setRequestType($ch);
		$this->__setData($ch, $data);
		$this->__setHeaders($ch);
		
		$data = $this->__runRequest($ch);
		$file_id = $data->file;
		return new File($file_id, $this->api);		
	}
	
	/**
	 * Upload file from file pointer
	 *
	 * @param resourse $fp
	 * @return File
	 **/
	public function fromResource($fp)
	{
		$tmpfile = tempnam(sys_get_temp_dir(), 'ucr');
		$temp = fopen($tmpfile, 'w');
		while (!feof($fp)) {
			fwrite($temp, fread($fp, 8192));
		}				
		fclose($temp);
		fclose($fp);
		
		$data = array(
				'UPLOADCARE_PUB_KEY' => $this->api->getPublicKey(),
				'file' => '@'.$tmpfile,
		);
		$ch = $this->__initRequest('base');
		$this->__setRequestType($ch);
		$this->__setData($ch, $data);
		$this->__setHeaders($ch);
			
		$data = $this->__runRequest($ch);
		$file_id = $data->file;
		return new File($file_id, $this->api);
	}	
	
	/**
	 * Upload file from string using mime-type.
	 *
	 * @param string $content
	 * @param string $mime_type
	 * @return File
	 **/
	public function fromContent($content, $mime_type)
	{
		$tmpfile = tempnam(sys_get_temp_dir(), 'ucr');
		$temp = fopen($tmpfile, 'w');
		fwrite($temp, $content);
		fclose($temp);
	
		$data = array(
				'UPLOADCARE_PUB_KEY' => $this->api->getPublicKey(),
				'file' => sprintf('@%s;type=%s', $tmpfile, $mime_type),
		);
		$ch = $this->__initRequest('base');
		$this->__setRequestType($ch);
		$this->__setData($ch, $data);
		$this->__setHeaders($ch);
			
		$data = $this->__runRequest($ch);
		$file_id = $data->file;
		return new File($file_id, $this->api);
	}	
	
	/**
	 * Init upload request and return curl resource
	 * 
	 * @param array $data
	 * @return resource
	 **/
	private function __initRequest($type, $data = null)
	{
		$url = sprintf('https://%s/%s/', $this->host, $type);
		if (is_array($data)) {
			$url = sprintf('%s?%s', $url, http_build_query($data));
		}
		$ch = curl_init($url);
		return $ch;
	}
	
	/**
	 * Set request type for curl resrouce
	 * 
	 * @param resource $ch
	 * @return void
	 **/
	private function __setRequestType($ch)
	{
		curl_setopt($ch, CURLOPT_POST, true);
	}
	
	/**
	 * Set all the headers for request and set returntrasfer.
	 *
	 * @param resource $ch. Curl resource.
	 * @return void
	 **/
	private function __setHeaders($ch)
	{
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
			'User-Agent: PHP Uploadcare Module '.$this->api->version,
		));
	}	
	
	/**
	 * Set data to be posted on request
	 * 
	 * @param resource $ch. Curl resource
	 * @param array $data
	 * @return void
	 **/
	private function __setData($ch, $data = array())
	{
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
	}
	
	/**
	 * Run prepared curl request.
	 * Throws Exception of not 200 http code
	 * 
	 * @param resource $ch. Curl resource
	 * @throws Exception
	 * @return array
	 **/
	private function __runRequest($ch)
	{
		$data = curl_exec($ch);
		$ch_info = curl_getinfo($ch);
		if ($ch_info['http_code'] != 200) {
			throw new \Exception('Request returned unexpected http code '.$ch_info['http_code'].'. '.$data);
		}
		curl_close($ch);
		return json_decode($data);		
	}
}